using System;
using CodePlex.DnD4eCampaignManager.DnD4e.Interfaces;

namespace CodePlex.DnD4eCampaignManager.DnD4e
{
    public class HealingSurges : IHealingSurges, IEquatable<HealingSurges>
    {
        private readonly IHitPoints _hitPoints;
        private int _healingSurgesCurrent;
        private int? _healingSurgesMaximum;

        public HealingSurges(IHitPoints hitPoints)
        {
            _hitPoints = hitPoints;
        }

        public int FailedDeathSaves { get; set; }

        public int HealingSurgesCurrent
        {
            get { return _healingSurgesCurrent; }
            set
            {
                _healingSurgesCurrent = value;
                EnforceBoundryConditionsOnHealingSurgesCurrent();
            }
        }

        public int HealingSurgesMaximum
        {
            get { return _healingSurgesMaximum.GetValueOrDefault(0); }
            set { _healingSurgesMaximum = value; }
        }

        public int HealingSurgeValue { get; set; }

        public int HitPointsBloodied
        {
            get { return _hitPoints.HitPointsBloodied; }
        }

        public int HitPointsCurrent
        {
            get { return _hitPoints.HitPointsCurrent; }
            set { _hitPoints.HitPointsCurrent = value; }
        }

        public int HitPointsMaximum
        {
            get { return _hitPoints.HitPointsMaximum; }
            set { _hitPoints.HitPointsMaximum = value; }
        }

        public int HitPointsTemporary
        {
            get { return _hitPoints.HitPointsTemporary; }
            set { _hitPoints.HitPointsTemporary = value; }
        }

        public bool IsBloodied
        {
            get { return _hitPoints.IsBloodied; }
        }

        public override bool Equals(object obj)
        {
            if ( ReferenceEquals(null, obj) )
            {
                return false;
            }
            if ( ReferenceEquals(this, obj) )
            {
                return true;
            }
            if ( obj.GetType() != typeof ( HealingSurges ) )
            {
                return false;
            }
            return Equals((HealingSurges) obj);
        }

        public override int GetHashCode()
        {
            unchecked
            {
                int result = ( _hitPoints != null ? _hitPoints.GetHashCode() : 0 );
                result = ( result * 397 ) ^ _healingSurgesCurrent;
                result = ( result * 397 ) ^ ( _healingSurgesMaximum.HasValue ? _healingSurgesMaximum.Value : 0 );
                result = ( result * 397 ) ^ HealingSurgeValue;
                return result;
            }
        }

        public void Damage(int hitPointsLost)
        {
            _hitPoints.Damage(hitPointsLost);
        }

        public bool Equals(HealingSurges other)
        {
            if ( ReferenceEquals(null, other) )
            {
                return false;
            }
            if ( ReferenceEquals(this, other) )
            {
                return true;
            }
            return Equals(other._hitPoints, _hitPoints) && other._healingSurgesCurrent == _healingSurgesCurrent &&
                   other._healingSurgesMaximum.Equals(_healingSurgesMaximum) && other.HealingSurgeValue == HealingSurgeValue;
        }

        public void Heal(int hitPointsRecovered)
        {
            _hitPoints.Heal(hitPointsRecovered);
        }

        public void SpendHealingSurge()
        {
            bool hasSurges = HealingSurgesCurrent > 0;
            bool needsHealing = _hitPoints.HitPointsCurrent < _hitPoints.HitPointsMaximum;
            Console.Out.WriteLine("hasSurges = {0}", hasSurges);
            Console.Out.WriteLine("needsHealing = {0}", needsHealing);
            if ( hasSurges && needsHealing )
            {
                _hitPoints.Heal(SurgeValue());
                HealingSurgesCurrent = HealingSurgesCurrent - 1;
            }
        }

        private void EnforceBoundryConditionsOnHealingSurgesCurrent()
        {
            bool valueExceedsMaximum = _healingSurgesCurrent >= HealingSurgesMaximum;
            if ( _healingSurgesMaximum.HasValue && valueExceedsMaximum )
            {
                _healingSurgesCurrent = HealingSurgesMaximum;
            }
            else if ( _healingSurgesCurrent < 0 )
            {
                _healingSurgesCurrent = 0;
            }
        }

        private int SurgeValue()
        {
            int surgeValue = _hitPoints.HitPointsMaximum / 4;
            Console.Out.WriteLine("surgeValue = {0}", surgeValue);
            return surgeValue;
        }

        public static bool operator ==(HealingSurges left, HealingSurges right)
        {
            return Equals(left, right);
        }

        public static bool operator !=(HealingSurges left, HealingSurges right)
        {
            return !Equals(left, right);
        }
    }
}